#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/delay.h>

// Status enumeration, Used with most functions
#define MI_OK													0
#define MI_NOTAGERR												1
#define MI_ERR													2

// MFRC522 Commands
#define PCD_IDLE										0x00		// NO action; Cancel the current command
#define PCD_AUTHENT										0x0E  	// Authentication Key
#define PCD_RECEIVE										0x08   	// Receive Data
#define PCD_TRANSMIT									0x04   	// Transmit data
#define PCD_TRANSCEIVE								    0x0C   	// Transmit and receive data,
#define PCD_RESETPHASE								    0x0F   	// Reset
#define PCD_CALCCRC										0x03   	// CRC Calculate

// Mifare_One card command word
#define PICC_REQA										0x26   	// find the antenna area does not enter hibernation
#define PICC_REQALL										0x52   	// find all the cards antenna area
#define PICC_ANTICOLL									0x93   	// anti-collision
#define PICC_SElECTTAG								0x93   	// election card
#define PICC_AUTHENT1A								0x60   	// authentication key A
#define PICC_AUTHENT1B								0x61   	// authentication key B
#define PICC_READ											0x30   	// Read Block
#define PICC_WRITE										0xA0   	// write block
#define PICC_DECREMENT								0xC0   	// debit
#define PICC_INCREMENT								0xC1   	// recharge
#define PICC_RESTORE									0xC2   	// transfer block data to the buffer
#define PICC_TRANSFER									0xB0   	// save the data in the buffer
#define PICC_HALT											0x50   	// Sleep

// MFRC522 Registers
// Page 0: Command and Status
#define MFRC522_REG_RESERVED00					0x00
#define MFRC522_REG_COMMAND						0x01
#define MFRC522_REG_COMM_IE_N					0x02
#define MFRC522_REG_DIV1_EN						0x03
#define MFRC522_REG_COMM_IRQ					0x04
#define MFRC522_REG_DIV_IRQ						0x05
#define MFRC522_REG_ERROR							0x06
#define MFRC522_REG_STATUS1						0x07
#define MFRC522_REG_STATUS2						0x08
#define MFRC522_REG_FIFO_DATA					0x09
#define MFRC522_REG_FIFO_LEVEL				0x0A   //  Indicates the number of bytes stored in the FIFO
#define MFRC522_REG_WATER_LEVEL				0x0B
#define MFRC522_REG_CONTROL						0x0C
#define MFRC522_REG_BIT_FRAMING				0x0D
#define MFRC522_REG_COLL							0x0E
#define MFRC522_REG_RESERVED01				0x0F
// Page 1: Command
#define MFRC522_REG_RESERVED10				0x10
#define MFRC522_REG_MODE							0x11
#define MFRC522_REG_TX_MODE						0x12
#define MFRC522_REG_RX_MODE						0x13
#define MFRC522_REG_TX_CONTROL				0x14
#define MFRC522_REG_TX_AUTO						0x15
#define MFRC522_REG_TX_SELL						0x16
#define MFRC522_REG_RX_SELL						0x17
#define MFRC522_REG_RX_THRESHOLD			0x18
#define MFRC522_REG_DEMOD							0x19
#define MFRC522_REG_RESERVED11				0x1A
#define MFRC522_REG_RESERVED12				0x1B
#define MFRC522_REG_MIFARE						0x1C
#define MFRC522_REG_RESERVED13				0x1D
#define MFRC522_REG_RESERVED14				0x1E
#define MFRC522_REG_SERIALSPEED				0x1F
// Page 2: CFG
#define MFRC522_REG_RESERVED20				0x20
#define MFRC522_REG_CRC_RESULT_M			0x21
#define MFRC522_REG_CRC_RESULT_L			0x22
#define MFRC522_REG_RESERVED21				0x23
#define MFRC522_REG_MOD_WIDTH					0x24
#define MFRC522_REG_RESERVED22				0x25
#define MFRC522_REG_RF_CFG						0x26
#define MFRC522_REG_GS_N							0x27
#define MFRC522_REG_CWGS_PREG					0x28
#define MFRC522_REG__MODGS_PREG				0x29
#define MFRC522_REG_T_MODE						0x2A
#define MFRC522_REG_T_PRESCALER				0x2B
#define MFRC522_REG_T_RELOAD_H				0x2C
#define MFRC522_REG_T_RELOAD_L				0x2D
#define MFRC522_REG_T_COUNTER_VALUE_H	0x2E
#define MFRC522_REG_T_COUNTER_VALUE_L	0x2F
// Page 3:TestRegister
#define MFRC522_REG_RESERVED30				0x30
#define MFRC522_REG_TEST_SEL1					0x31
#define MFRC522_REG_TEST_SEL2					0x32
#define MFRC522_REG_TEST_PIN_EN				0x33
#define MFRC522_REG_TEST_PIN_VALUE		0x34
#define MFRC522_REG_TEST_BUS					0x35
#define MFRC522_REG_AUTO_TEST					0x36
#define MFRC522_REG_VERSION						0x37
#define MFRC522_REG_ANALOG_TEST				0x38
#define MFRC522_REG_TEST_ADC1					0x39
#define MFRC522_REG_TEST_ADC2					0x3A
#define MFRC522_REG_TEST_ADC0					0x3B
#define MFRC522_REG_RESERVED31				0x3C
#define MFRC522_REG_RESERVED32				0x3D
#define MFRC522_REG_RESERVED33				0x3E
#define MFRC522_REG_RESERVED34				0x3F

#define MFRC522_DUMMY									0x00		// Dummy byte
#define MFRC522_MAX_LEN								16			// Buf len byte

#define MFRC522_SPI_WRITE 0
#define MFRC522_SPI_READ 1

#define MFRC522_VERSION_BASE 0x90
#define MFRC522_VERSION_1 0x91
#define MFRC522_VERSION_2 0x92
#define MFRC522_VERSION_NUM(ver) ((ver)-MFRC522_VERSION_BASE)

// MFRC522 registers, see 9.2
#define MFRC522_COMMAND_REG 0x1
#define MFRC522_FIFO_DATA_REG 0x9
#define MFRC522_FIFO_LEVEL_REG 0xA
#define MFRC522_VERSION_REG 0x37

// Helpers for command register values
#define MFRC522_COMMAND_REG_RCV_ON 0
#define MFRC522_COMMAND_REG_RCV_OFF 1
#define MFRC522_COMMAND_REG_POWER_DOWN_ON 1
#define MFRC522_COMMAND_REG_POWER_DOWN_OFF 0

#define MFRC522_FIFO_LEVEL_REG_FLUSH_SHIFT 7
#define MFRC522_FIFO_LEVEL_REG_LEVEL_MASK 0x7F

#define MFRC522_COMMAND_REG_RCV_OFF_SHIFT 5
#define MFRC522_COMMAND_REG_POWER_DOWN_SHIFT 4
#define MFRC522_COMMAND_REG_COMMAND_MASK 0xF

// MFRC522 commands, see 10.3
#define MFRC522_COMMAND_IDLE 0b0000
#define MFRC522_COMMAND_MEM 0b0001
#define MFRC522_COMMAND_GENERATE_RANDOM_ID 0b0010
#define MFRC522_COMMAND_CALC_CRC 0b0011
#define MFRC522_COMMAND_TRANSMIT 0b0100
#define MFRC522_COMMAND_NO_CMD_CHANGE 0b0111
#define MFRC522_COMMAND_RECEIVE 0b1000
#define MFRC522_COMMAND_TRANSCEIVE 0b1100
#define MFRC522_COMMAND_MF_AUTHENT 0b1110
#define MFRC522_COMMAND_SOFT_RESET 0b1111

#define MFRC522_MEM_SIZE 25

struct spi_device *mfrc522_spi;

static void wait_for_cmd(void);

// RC522
u8 MFRC522_Check(void);
void MFRC522_WriteRegister(u8 addr, u8 val);
u8 MFRC522_ReadRegister(u8 addr);
void MFRC522_SetBitMask(u8 reg, u8 mask);
void MFRC522_ClearBitMask(u8 reg, u8 mask);
u8 MFRC522_Request(u8 reqMode, u8 *TagType);
u8 MFRC522_ToCard(u8 command, u8 *sendData, u8 sendLen, u8 *backData,
		uint16_t *backLen);
u8 MFRC522_Anticoll(u8 *serNum);
void MFRC522_Init(void);
void MFRC522_Reset(void);
void MFRC522_AntennaOn(void);
void MFRC522_AntennaOff(void);
void MFRC522_Halt(void);

/**
 * Abstraction on the format used to define the address bytes sent to the MFRC522
 * as part of an SPI transfer
 */
struct address_byte {
	u8 lsb :1; // 0
	u8 addr :6;
	u8 rw :1; // 1 -> Read, 0 -> Write
} __packed;

struct address_byte address_byte_build(u8 mode, u8 addr) {
	struct address_byte byte = { .rw = mode, .addr = addr, };

	return byte;
}

int mfrc522_register_write(struct spi_device *client, u8 reg, u8 value) {
	struct address_byte reg_write = address_byte_build(0, reg);
	u8 data[2] = { 0, value };

	// We cannot directly put reg_write in data[0] at init time
	memcpy(&data[0], &reg_write, sizeof(u8));
	return spi_write(client, &data, 2);
}

int mfrc522_register_read(struct spi_device *client, u8 reg, u8 *read_buff,
		u8 read_len) {
	size_t i;
	int ret;
	struct address_byte reg_read = address_byte_build(1, reg);

	for (i = 0; i < read_len; i++) {
		ret = spi_write_then_read(client, &reg_read, 1, read_buff + i, 1);
		if (ret < 0)
			return ret;
	}

	return read_len;
}

void MFRC522_CalculateCRC(u8 *pIndata, u8 len, u8 *pOutData) {
	u8 i, n;

	MFRC522_ClearBitMask(MFRC522_REG_DIV_IRQ, 0x04);			// CRCIrq = 0
	MFRC522_SetBitMask(MFRC522_REG_FIFO_LEVEL, 0x80);// Clear the FIFO pointer
	// Write_MFRC522(CommandReg, PCD_IDLE);

	// Writing data to the FIFO
	for (i = 0; i < len; i++)
		MFRC522_WriteRegister(MFRC522_REG_FIFO_DATA, *(pIndata + i));
	MFRC522_WriteRegister(MFRC522_REG_COMMAND, PCD_CALCCRC);

	// Wait CRC calculation is complete
	i = 0xFF;
	do {
		n = MFRC522_ReadRegister(MFRC522_REG_DIV_IRQ);
		i--;
	} while ((i != 0) && !(n & 0x04));							// CRCIrq = 1

	// Read CRC calculation result
	pOutData[0] = MFRC522_ReadRegister(MFRC522_REG_CRC_RESULT_L);
	pOutData[1] = MFRC522_ReadRegister(MFRC522_REG_CRC_RESULT_M);
}

void MFRC522_WriteRegister(u8 reg, u8 value) {
	mfrc522_register_write(mfrc522_spi, reg, value);
}

u8 MFRC522_ReadRegister(u8 reg) {
	u8 tmp;
	mfrc522_register_read(mfrc522_spi, reg, &tmp, 1);
	return tmp;
}

void MFRC522_SetBitMask(u8 reg, u8 mask) {
	MFRC522_WriteRegister(reg, MFRC522_ReadRegister(reg) | mask);
}

void MFRC522_ClearBitMask(u8 reg, u8 mask) {
	MFRC522_WriteRegister(reg, MFRC522_ReadRegister(reg) & (~mask));
}

void MFRC522_AntennaOn(void) {
	u8 temp;
	temp = MFRC522_ReadRegister(MFRC522_REG_TX_CONTROL);
	if (!(temp & 0x03))
		MFRC522_SetBitMask(MFRC522_REG_TX_CONTROL, 0x03);
}

void MFRC522_AntennaOff(void) {
	MFRC522_ClearBitMask(MFRC522_REG_TX_CONTROL, 0x03);
}

void MFRC522_Reset(void) {
	MFRC522_WriteRegister(MFRC522_REG_COMMAND, PCD_RESETPHASE);  //  0x0F
}

/**
 *  MFRC522.PDF page 67 .
 */
void startTimer(void) {
	MFRC522_SetBitMask(MFRC522_REG_CONTROL, 0x20);
}

void stopTimer(void) {
	MFRC522_SetBitMask(MFRC522_REG_CONTROL, 0x40);
}

/**
 *   TRunning,
 *   page 19 .
 */
void readTimerStatus(void) {
	u8 status;
	u8 timer;
	status = MFRC522_ReadRegister(MFRC522_REG_STATUS1);
	timer = status & 0x04;
	pr_info("timer status :%d \n", timer);
}

static void mfrc522_fifo_flush(void) {
	u8 flush_byte = 1 << MFRC522_FIFO_LEVEL_REG_FLUSH_SHIFT;

	mfrc522_register_write(mfrc522_spi, MFRC522_FIFO_LEVEL_REG, flush_byte);
}

static int mfrc522_fifo_write(const u8 *buf, size_t len) {
	size_t i;
	int ret;

	for (i = 0; i < len; i++) {
		ret = mfrc522_register_write(mfrc522_spi, MFRC522_FIFO_DATA_REG,
				buf[i]);
		if (ret < 0)
			return ret;
	}

	return 0;
}

int mfrc522_send_command(u8 rcv_off, u8 power_down, u8 command) {
	u8 command_byte = rcv_off << MFRC522_COMMAND_REG_RCV_OFF_SHIFT
			| power_down << MFRC522_COMMAND_REG_POWER_DOWN_SHIFT | command;

	if (mfrc522_register_write(mfrc522_spi, MFRC522_COMMAND_REG, command_byte)
			< 0)
		return -1;

	wait_for_cmd();

	return 0;
}

/**
 * Write 25 bytes of data into the MFRC522's internal memory
 *
 * @param data User input to write to the memory
 *
 * @return 0 on success, -1 on error
 */
static int mem_write(char *data) {
	// We know that data is zero-filled since we initialized it using
	// mfrc522_command_init()
	if (mfrc522_fifo_write(data, MFRC522_MEM_SIZE) < 0) {
		pr_err("[MFRC522] Couldn't write to FIFO\n");
		return -1;
	}

	mfrc522_send_command(MFRC522_COMMAND_REG_RCV_ON,
	MFRC522_COMMAND_REG_POWER_DOWN_OFF,
	MFRC522_COMMAND_MEM);
	pr_info("[MFRC522] Wrote data to memory\n");
	return 0;
}

/**
 *
 *  page 65.
 *
 * first write :
 *  MFRC522_WriteRegister(MFRC522_REG_FIFO_DATA, 0x23);
 MFRC522_WriteRegister(MFRC522_REG_FIFO_DATA, 0x24);
 MFRC522_WriteRegister(MFRC522_REG_FIFO_DATA, 0x25);
 MFRC522_WriteRegister(MFRC522_REG_FIFO_DATA, 0x26);
 MFRC522_WriteRegister(MFRC522_REG_FIFO_DATA, 0x27);
 *
 *
 */
void readfifo(void) {
//	u8 status = 0;
//	u8 status1 = 0;
	u8 temp;
	u8 temp2;
	temp2 = MFRC522_ReadRegister(MFRC522_REG_FIFO_LEVEL);
	if (temp2 == 0) {
		return;
	}
	pr_info("FIFO  temp2 :%d\n", temp2);

	while (temp2 > 0) {
		temp = MFRC522_ReadRegister(MFRC522_REG_FIFO_DATA);

//	u8 timer ;
//	status = MFRC522_ReadRegister(MFRC522_REG_T_RELOAD_H);

//	status1 = MFRC522_ReadRegister(MFRC522_REG_T_RELOAD_L);
//	timer = (status & 0x80) >> 7;

//	pr_info("Tauto :%d \n", status);
//	pr_info("Tauto :0x%x \n", status);

//	pr_info("Tauto :0x%x \n", status1);

		pr_info("FIFO :0x%x \n", temp);
		temp2--;

//	pr_info("MFRC522_REG_FIFO_LEVEL  :0x%x \n", temp2);

	}

//	pr_info("Tauto :%d \n", timer);
//	pr_info("Tauto :0x%x \n", timer);
}

void readErrorReg(void) {
	u8 temp;
	temp = MFRC522_ReadRegister(MFRC522_REG_ERROR);
	pr_info("ErrorReg :0x%x \n", temp);
}

void readStatus2Reg(void) {
	u8 temp;
	temp = MFRC522_ReadRegister(MFRC522_REG_STATUS2);
	pr_info("Status2Reg :0x%x \n", temp);
}

void readTCounterValReg(void) {
	u8 temp;
	temp = MFRC522_ReadRegister(MFRC522_REG_T_COUNTER_VALUE_H);
	pr_info("TCounterValReg_H :0x%x \n", temp);
	temp = MFRC522_ReadRegister(MFRC522_REG_T_COUNTER_VALUE_L);
	pr_info("TCounterValReg_L :0x%x \n", temp);
}

void readVersionReg(void) {
	u8 temp;
	temp = MFRC522_ReadRegister(MFRC522_REG_VERSION);
	pr_info("VersionReg :0x%x \n", temp);
}

int mfrc522_read_command(void) {
	u8 command_reg;
	int ret;
	ret = mfrc522_register_read(mfrc522_spi, MFRC522_COMMAND_REG, &command_reg,
			1);
	if (ret < 0)
		return ret;
	return command_reg & MFRC522_COMMAND_REG_COMMAND_MASK;
}

static void wait_for_cmd(void) {
	int cmd;
	do {
		cmd = mfrc522_read_command();
		pr_info("[MFRC522] Current command is: 0x%x\n", cmd);
	} while (cmd != MFRC522_COMMAND_IDLE);
}

/**
 *  page 14.
 *
 *
 *
 */
void readCommandReg(void) {
	u8 temp;
	temp = MFRC522_ReadRegister(MFRC522_REG_COMMAND);
	pr_info("CommandReg :0x%x \n", temp);
}

/**
 *  page 72  .
 *
 *
 *
 */
int RandomID(void) {
	u8 buffer[MFRC522_MEM_SIZE] = { 0 };
	// Clear the internal buffer
	if (mem_write(buffer) < 0)
		return -1;

	if (mfrc522_send_command(MFRC522_COMMAND_REG_RCV_ON,
	MFRC522_COMMAND_REG_POWER_DOWN_OFF,
	MFRC522_COMMAND_GENERATE_RANDOM_ID) < 0)
		return -1;

	mfrc522_fifo_flush();
	if (mfrc522_send_command(MFRC522_COMMAND_REG_RCV_ON,
	MFRC522_COMMAND_REG_POWER_DOWN_OFF,
	MFRC522_COMMAND_MEM) < 0)
		return -1;
	readfifo();
	return 0;
}

void readtmp(void) {
//	u8 status = 0;
//	u8 status1 = 0;
	u8 temp;
	u8 temp2;

	temp2 = MFRC522_ReadRegister(MFRC522_REG_FIFO_LEVEL);

	if (temp2 == 0) {
		return;
	}

	temp = MFRC522_ReadRegister(MFRC522_REG_FIFO_DATA);

//	u8 timer ;
//	status = MFRC522_ReadRegister(MFRC522_REG_T_RELOAD_H);

//	status1 = MFRC522_ReadRegister(MFRC522_REG_T_RELOAD_L);
//	timer = (status & 0x80) >> 7;

//	pr_info("Tauto :%d \n", status);
//	pr_info("Tauto :0x%x \n", status);

//	pr_info("Tauto :0x%x \n", status1);

	pr_info("FIFO :0x%x \n", temp);

	pr_info("MFRC522_REG_FIFO_LEVEL  :0x%x \n", temp2);

//	pr_info("Tauto :%d \n", timer);
//	pr_info("Tauto :0x%x \n", timer);
}

void MFRC522_Init(void) {
	MFRC522_Reset();
	printk(KERN_INFO "after Reset: CommIRqReg: 0x%x\n",
			MFRC522_ReadRegister(MFRC522_REG_COMM_IRQ));

	printk(KERN_INFO "after Reset: MFRC522_REG_T_MODE: 0x%x\n",
			MFRC522_ReadRegister(MFRC522_REG_T_MODE));
	printk(KERN_INFO "after Reset: MFRC522_REG_T_PRESCALER: 0x%x\n",
			MFRC522_ReadRegister(MFRC522_REG_T_PRESCALER));
	printk(KERN_INFO "after Reset: MFRC522_REG_T_RELOAD_H: 0x%x\n",
			MFRC522_ReadRegister(MFRC522_REG_T_RELOAD_H));
	printk(KERN_INFO "after Reset: MFRC522_REG_T_RELOAD_L: 0x%x\n",
			MFRC522_ReadRegister(MFRC522_REG_T_RELOAD_L));

//	printk(KERN_INFO "677 = 0x%x\n",677);
//	printk(KERN_INFO "0xd3e = %d\n",0xd3e);

	MFRC522_WriteRegister(MFRC522_REG_T_MODE, 0x8D);
	MFRC522_WriteRegister(MFRC522_REG_T_PRESCALER, 0x3E);
	MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_L, 30);
	MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_H, 0);

//	MFRC522_WriteRegister(MFRC522_REG_T_MODE, 0x0D);
//	MFRC522_WriteRegister(MFRC522_REG_T_PRESCALER, 0x3E);
//	MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_L, 0);
//	MFRC522_WriteRegister(MFRC522_REG_T_RELOAD_H, 0);

	MFRC522_WriteRegister(MFRC522_REG_RF_CFG, 0x70);				// 48dB gain
	MFRC522_WriteRegister(MFRC522_REG_TX_AUTO, 0x40);

	MFRC522_WriteRegister(MFRC522_REG_MODE, 0x3D);
	MFRC522_AntennaOn();
	printk(KERN_INFO "after init 1: CommIRqReg: 0x%x\n",
			MFRC522_ReadRegister(MFRC522_REG_COMM_IRQ));
}

int mfrc522_get_version(void) {
	u8 version;
	int ret;

	ret = mfrc522_register_read(mfrc522_spi, MFRC522_VERSION_REG, &version, 1);

	if (ret < 0)
		return ret;

	return version;
}

/**
 * 新卡的出厂密码一般是密码A和密码B都是6个FF.
 */
uint8_t MFRC522_Anticoll(uint8_t *serNum) {
	uint8_t status;
	uint8_t i;
	uint8_t serNumCheck = 0;
	uint16_t unLen;

	MFRC522_WriteRegister(MFRC522_REG_BIT_FRAMING, 0x00);// TxLastBists = BitFramingReg[2..0]
	serNum[0] = PICC_ANTICOLL;
	serNum[1] = 0x20;
	status = MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);
	if (status == MI_OK) {
		// Check card serial number
		for (i = 0; i < 4; i++)
			serNumCheck ^= serNum[i];
		if (serNumCheck != serNum[i])
			status = MI_ERR;
	}
	return status;
}

u8 MFRC522_ToCard(u8 command, u8 *sendData, u8 sendLen, u8 *backData,
		uint16_t *backLen) {
	u8 status = MI_ERR;
	u8 irqEn = 0x00;
	u8 waitIRq = 0x00;
	u8 lastBits;
	u8 n;
	uint16_t i;

	switch (command) {
	case PCD_AUTHENT: {
		irqEn = 0x12;
		waitIRq = 0x10;
		break;
	}
	case PCD_TRANSCEIVE: {
		irqEn = 0x77;
		waitIRq = 0x30;
		break;
	}
	default:
		break;
	}

	MFRC522_WriteRegister(MFRC522_REG_COMM_IE_N, irqEn | 0x80);
	MFRC522_ClearBitMask(MFRC522_REG_COMM_IRQ, 0x80);
	MFRC522_SetBitMask(MFRC522_REG_FIFO_LEVEL, 0x80);
	MFRC522_WriteRegister(MFRC522_REG_COMMAND, PCD_IDLE);

	// Writing data to the FIFO
	for (i = 0; i < sendLen; i++)
		MFRC522_WriteRegister(MFRC522_REG_FIFO_DATA, sendData[i]);

	// Execute the command
	MFRC522_WriteRegister(MFRC522_REG_COMMAND, command);
	if (command == PCD_TRANSCEIVE)
		MFRC522_SetBitMask(MFRC522_REG_BIT_FRAMING, 0x80);// StartSend=1,transmission of data starts

	// Waiting to receive data to complete
	i = 50;	//i according to the clock frequency adjustment, the operator M1 card maximum waiting time 25ms
	pr_info("waitIRq :  0x%x", waitIRq);
	do {
		mdelay(1);
		// CommIrqReg[7..0]
		// Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
		n = MFRC522_ReadRegister(MFRC522_REG_COMM_IRQ);
		pr_info("MFRC522_REG_COMM_IRQ :  0x%x", n);
		i--;
	} while ((i != 0) && !(n & 0x01) && !(n & waitIRq));

	pr_info("i :  %d", i);

	if (i == 0) {
		pr_alert("error");
	}

//	if(1) return 0 ;

	MFRC522_ClearBitMask(MFRC522_REG_BIT_FRAMING, 0x80);		// StartSend=0

	if (i != 0) {
		if (!(MFRC522_ReadRegister(MFRC522_REG_ERROR) & 0x1B)) {
			status = MI_OK;
			if (n & irqEn & 0x01)
				status = MI_NOTAGERR;
			if (command == PCD_TRANSCEIVE) {
				n = MFRC522_ReadRegister(MFRC522_REG_FIFO_LEVEL);

				pr_info("FIFO bytes :  %d", n);

				lastBits = MFRC522_ReadRegister(MFRC522_REG_CONTROL) & 0x07;
				if (lastBits)
					*backLen = (n - 1) * 8 + lastBits;
				else
					*backLen = n * 8;
				if (n == 0)
					n = 1;
				if (n > MFRC522_MAX_LEN)
					n = MFRC522_MAX_LEN;
				for (i = 0; i < n; i++)
					backData[i] = MFRC522_ReadRegister(MFRC522_REG_FIFO_DATA);// Reading the received data in FIFO
			}
		} else
			status = MI_ERR;
	}
//	pr_info("backLen :  %d",*backLen);
	pr_info("MFRC522_ToCard end, status:%d \n", status);
	return status;
}

void MFRC522_Halt(void) {
	uint16_t unLen;
	u8 buff[4];

	buff[0] = PICC_HALT;
	buff[1] = 0;
	MFRC522_CalculateCRC(buff, 2, &buff[2]);
	MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &unLen);
}

/**
 *
 *
 *
 *
 *
 */
u8 MFRC522_Request(u8 reqMode, u8 *TagType) {
	u8 status;
	uint16_t backBits;								// The received data bits

	pr_info("MFRC522_Request start\n");
	MFRC522_WriteRegister(MFRC522_REG_BIT_FRAMING, 0x07);// TxLastBists = BitFramingReg[2..0]
	TagType[0] = reqMode;
	status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);
	if ((status != MI_OK) || (backBits != 0x10))
		status = MI_ERR;

	pr_info("MFRC522_Request end, status:%d \n", status);
	return status;
}

/**
 * S50.pdf, page 6 .
 *
 */
u8 MFRC522_Read(u8 block_addr) {
	u8 status;
	uint16_t unLen;
	int i;
	u8 recvData[18] = { };
	recvData[0] = PICC_READ;
	recvData[1] = block_addr;
	MFRC522_CalculateCRC(recvData, 2, &recvData[2]);
	status = MFRC522_ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);
	pr_info("MFRC522_Read unLen: %d\n", unLen);
	if ((status != MI_OK) || (unLen != 0x90)) {
		status = MI_ERR;
		pr_alert("MFRC522_Read status fail: %d\n", status);
		return status;
	}

	for (i = 0; i < 18; i++) {
		pr_info("recvData_%d: 0x%x\n", i, recvData[i]);
	}
	pr_alert("MFRC522_Read status: %d\n", status);
	return status;
}

uint8_t MFRC522_Write(uint8_t blockAddr) {
	uint8_t writeData[16] = { };
	uint8_t status;
	uint16_t recvBits;
	uint8_t i;
	uint8_t buff[18];

	writeData[6] = 0xff;
	writeData[7] = 0x07;
	writeData[8] = 0x80;
	writeData[9] = 0x69;

	writeData[10] = 0xff;
	writeData[11] = 0xff;
	writeData[12] = 0xff;
	writeData[13] = 0xff;
	writeData[14] = 0xff;
	writeData[15] = 0xff;

	buff[0] = PICC_WRITE;
	buff[1] = blockAddr;
	MFRC522_CalculateCRC(buff, 2, &buff[2]);
	status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);
	if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
		status = MI_ERR;
	if (status == MI_OK) {
		// Data to the FIFO write 16Byte
		for (i = 0; i < 16; i++)
			buff[i] = *(writeData + i);
		MFRC522_CalculateCRC(buff, 16, &buff[16]);
		status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);
		if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
			status = MI_ERR;
	}
	pr_alert("MFRC522_Write status: %d \n", status);
	return status;
}

u8 MFRC522_decrment_value_block(u8 blockAddr) {
	u8 writeData[16] = { };
	u8 status;
	u32 pValue = 1;
	uint16_t unLen = 0;
	writeData[0] = PICC_DECREMENT;
	writeData[1] = blockAddr;
	MFRC522_CalculateCRC(writeData, 2, &writeData[2]);
	status = MFRC522_ToCard(PCD_TRANSCEIVE, writeData, 4, writeData, &unLen);

	pr_info("writeData[0]: 0x%x\n",writeData[0]);

	if ((status != MI_OK)  || (unLen!=4) || ((writeData[0] & 0x0F) != 0x0A)) {
		status = MI_ERR;
	}

	if (status == MI_OK) {
		pr_info("ok  1\n");
		memcpy(writeData, &pValue, 4);
		MFRC522_CalculateCRC(writeData, 4, &writeData[4]);
		unLen = 0;
		status = MFRC522_ToCard(PCD_TRANSCEIVE, writeData, 6, writeData,
				&unLen);
		if (status != MI_ERR) {
			status = MI_OK;
		}
	}

	if (status == MI_OK) {
		pr_info("ok 2\n");
		writeData[0] = PICC_TRANSFER;
		writeData[1] = blockAddr;
		unLen = 0;
		MFRC522_CalculateCRC(writeData, 2, &writeData[2]);
		status = MFRC522_ToCard(PCD_TRANSCEIVE, writeData, 4, writeData,
				&unLen);

		if ((status != MI_OK) || (unLen != 4)
				|| ((writeData[0] & 0x0F) != 0x0A)) {
			status = MI_ERR;
		}
	}
	pr_alert("MFRC522_decrment_value_block status: %d \n", status);
	return status;
}


u8 MFRC522_incrment_value_block(u8 blockAddr) {
	u8 writeData[16] = { };
	u8 status;
	u32 pValue = 1;
	uint16_t unLen = 0;
	writeData[0] = PICC_INCREMENT;
	writeData[1] = blockAddr;
	MFRC522_CalculateCRC(writeData, 2, &writeData[2]);
	status = MFRC522_ToCard(PCD_TRANSCEIVE, writeData, 4, writeData, &unLen);

	pr_info("writeData[0]: 0x%x\n",writeData[0]);

	if ((status != MI_OK)  || (unLen!=4) || ((writeData[0] & 0x0F) != 0x0A)) {
		status = MI_ERR;
	}

	if (status == MI_OK) {
		pr_info("ok  1\n");
		memcpy(writeData, &pValue, 4);
		MFRC522_CalculateCRC(writeData, 4, &writeData[4]);
		unLen = 0;
		status = MFRC522_ToCard(PCD_TRANSCEIVE, writeData, 6, writeData,
				&unLen);
		if (status != MI_ERR) {
			status = MI_OK;
		}
	}

	if (status == MI_OK) {
		pr_info("ok 2\n");
		writeData[0] = PICC_TRANSFER;
		writeData[1] = blockAddr;
		unLen = 0;
		MFRC522_CalculateCRC(writeData, 2, &writeData[2]);
		status = MFRC522_ToCard(PCD_TRANSCEIVE, writeData, 4, writeData,
				&unLen);

		if ((status != MI_OK) || (unLen != 4)
				|| ((writeData[0] & 0x0F) != 0x0A)) {
			status = MI_ERR;
		}
	}
	pr_alert("MFRC522_incrment_value_block status: %d \n", status);
	return status;
}

/**
 * S50.pdf page 8  .
 *  https://blog.csdn.net/qq1113512618/article/details/106881725
 *
 */
u8 MFRC522_generate_value_block(u8 blockAddr) {
	u8 writeData[16] = { };
	u8 status;
	uint16_t recvBits;
	u8 i;
	u8 buff[18];

	u32 value = 0;
	u32 value_inverted = ~value;
	u8 addr = 1;
	u8 addr_inverted = ~addr;

	writeData[0] = value;
	writeData[1] = value >> 8 & 0xff;
	writeData[2] = value >> 16 & 0xff;
	writeData[3] = value >> 24 & 0xff;

	writeData[4] = value_inverted;
	writeData[5] = value_inverted >> 8 & 0xff;
	writeData[6] = value_inverted >> 16 & 0xff;
	writeData[7] = value_inverted >> 24 & 0xff;

	writeData[8] = value;
	writeData[9] = value >> 8 & 0x0f;
	writeData[10] = value >> 16 & 0x0f;
	writeData[11] = value >> 24 & 0x0f;

	writeData[12] = addr;
	writeData[13] = addr_inverted;
	writeData[14] = addr;
	writeData[15] = addr_inverted;

	buff[0] = PICC_WRITE;
	buff[1] = blockAddr;

	pr_info("value_inverted: 0x%x \n", value_inverted);
	pr_info("addr_inverted: 0x%x \n", addr_inverted);

	MFRC522_CalculateCRC(buff, 2, &buff[2]);
	status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);
	if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
		status = MI_ERR;
	if (status == MI_OK) {
		// Data to the FIFO write 16Byte
		for (i = 0; i < 16; i++)
			buff[i] = *(writeData + i);
		MFRC522_CalculateCRC(buff, 16, &buff[16]);
		status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);
		if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
			status = MI_ERR;
	}
	pr_alert("MFRC522_generate_value_block status: %d \n", status);
	return status;
}

/**
 * Authentication操作的卡应答以AE位给出，在PCD中由Status2Reg寄存器第4位标志，0为失败，1为成功.

 使用格式：1B模式 + 1B块地址 + 6B密码 + 4B卡片序列号

 块地址：指定非接触卡存储中某一个KEYSET
 模式：分A密码和B密码认证，A命令用0x60，B命令用0X61
 密码：需要视非接触卡情况而定，一般初始使用时密码均为F
 卡序列号：从防冲突中获取
 返回值：认证成功status寄存器对应位置1。
 *
 *  新卡的出厂密码A和密码B都是6个FF.
 *
 *  MFRC522.PDF  page 74  .
 *
 *
 *
 *
 */
u8 MFRC522_Auth(u8 *uid, u8 block_addr) {
	u8 status = 0;
	uint16_t backBits; // The received data bits
	u8 cmd[12] = { };

//	模式：分A密码和B密码认证，A命令用0x60，B命令用0X61
	cmd[0] = 0x61;

	cmd[1] = block_addr;

	cmd[2] = 0xFF;
	cmd[3] = 0xFF;
	cmd[4] = 0xFF;
	cmd[5] = 0xFF;
	cmd[6] = 0xFF;
	cmd[7] = 0xFF;

	cmd[8] = uid[0];
	cmd[9] = uid[1];
	cmd[10] = uid[2];
	cmd[11] = uid[3];

	pr_info("MFRC522_Auth start\n");
//	MFRC522_WriteRegister(MFRC522_REG_BIT_FRAMING, 0x00); // TxLastBists = BitFramingReg[2..0]
	status = MFRC522_ToCard(PCD_AUTHENT, cmd, 12, cmd, &backBits);
	if (status == MI_OK && (MFRC522_ReadRegister(MFRC522_REG_STATUS2) & 0x08)) {
		pr_info("MFRC522_Auth end, success\n");
		status = MFRC522_Read(block_addr);
		if (status == MI_OK) {
//			status = MFRC522_Write(block_addr);
//			status = MFRC522_generate_value_block(block_addr);
//
//			if (status == MI_OK) {
				status = MFRC522_decrment_value_block(block_addr);
//			}

			if (status == MI_OK) {
				status = MFRC522_Read(block_addr);
			}
		}
	} else {
		pr_info("MFRC522_Auth end, fail\n");
		status = MI_ERR;
	}
	return status;
}

/**
 * https://blog.csdn.net/weixin_42889383/article/details/103892749
 */
u8 MFRC522_Select(u8 *uid) {
	u8 cmd[9] = { };
	u8 status;
	uint16_t backBits; // The received data bits
	cmd[0] = PICC_SElECTTAG;
	cmd[1] = 0x70;
	cmd[2] = uid[0];
	cmd[3] = uid[1];
	cmd[4] = uid[2];
	cmd[5] = uid[3];
	cmd[6] = uid[4];
	MFRC522_CalculateCRC(cmd, 7, &cmd[7]);
	pr_info("MFRC522_Select start\n");
	MFRC522_WriteRegister(MFRC522_REG_BIT_FRAMING, 0x00); // TxLastBists = BitFramingReg[2..0]
	status = MFRC522_ToCard(PCD_TRANSCEIVE, cmd, 9, cmd, &backBits);
	if ((status != MI_OK) || (backBits != 24)) {
		pr_info("MFRC522_Select end,  error\n");
		status = MI_ERR;
		return status;
	}
	pr_info("cmd 0: 0x%x \n", cmd[0]);
	pr_info("MFRC522_Select end, status:%d \n", status);
	status = MFRC522_Auth(uid, 4);
	return status;
}

u8 MFRC522_Check(void) {
	u8 id[16] = { };
	u8 status;
	pr_info("MFRC522_Check start \n");

	pr_info("send REQA\n");

	/**
	 *   fcd-14443-3.pdf
	 *   6.4.2
	 */
	status = MFRC522_Request(PICC_REQA, id);	// Find cards, return card type

	pr_info("received ATQA:0x%x", id[0]);
//	pr_info("received ATQA:0x%x",id[1]);

	pr_info("UID size:0x%x", (id[0] & 0b11000000) >> 6);

	if (status != MI_OK) {
		pr_info("no card detected \n");
		return -1;
	}

	pr_info("start Anticollision \n");

//	防冲突：0x93，0x20，返回得到4B的卡ID + 1B校验(异或)
	status = MFRC522_Anticoll(id);// Card detected. Anti-collision, return card serial number 4 bytes
//	MFRC522_Halt();    // Command card into hibernation

	pr_info("id : %x,%x,%x,%x,%x\n", id[0], id[1], id[2], id[3], id[4]);
//	pr_info("id : %x,%x,%x,%x,%x\n", id[5],id[6],id[7],id[8],id[9]);
	if (status == MI_OK) {
		status = MFRC522_Select(id);
	}

	return status;
}

/** Detect if the device we are talking to is an MFRC522 using the VersionReg,
 * section 9.3.4.8 of the datasheet
 *
 * @client SPI device
 *
 * @return -1 if not an MFRC522, version number otherwise
 */
static int mfrc522_detect(struct spi_device *client) {
	u8 version = mfrc522_get_version();
	switch (version) {
	case MFRC522_VERSION_1:
	case MFRC522_VERSION_2:
		version = MFRC522_VERSION_NUM(version);
		pr_info("[MFRC522] MFRC522 version %d detected\n", version);
		return version;
	default:
		pr_info("[MFRC522] this chip is not an MFRC522: 0x%x\n", version);
	}

	return -1;
}

static int rc522_probe(struct spi_device *client) {
	pr_err("rc522_probe\n");
	printk(KERN_ALERT "rc522_probe\n");
	printk(KERN_ALERT "client->max_speed_hz %d \n", client->max_speed_hz);
	mfrc522_spi = client;
	mfrc522_detect(client);
	MFRC522_Init();
	printk(KERN_INFO "before check: CommIRqReg: 0x%x\n",
			MFRC522_ReadRegister(MFRC522_REG_COMM_IRQ));
	MFRC522_Check();
	return 0;
}

static int rc522_remove(struct spi_device *spi) {
	pr_err("rc522_remove\n");
	printk(KERN_ALERT "rc522_remove\n");
	return 0;
}

static const struct of_device_id rc522_of_match_ids[] = { { .compatible =
		"nxp,rc522", }, { } };

static struct spi_driver rc522_driver = { .driver = { .name = "mifare", .owner =
THIS_MODULE, .of_match_table = of_match_ptr(rc522_of_match_ids), }, .probe =
		rc522_probe, .remove = rc522_remove, };

static int __init rc522_init(void)
{
  printk(KERN_ALERT "rc522_init\n");
return spi_register_driver(&rc522_driver);;
}

static void __exit rc522_exit(void)
{
  printk(KERN_ALERT "rc522_exit\n");
  spi_unregister_driver(&rc522_driver);  	
}

module_init(rc522_init);
module_exit(rc522_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("aaaaa");
MODULE_DESCRIPTION("RF Mifare card driver");
MODULE_VERSION("1.0");
